<?php
/**
 *
 *
 */
namespace Yz\modules\Generic;

use Yz_Array,
    Yz_Int,
    Yz_Controller_Exception_InvalidArgument as CtlrArgumentError,
    Yz_Exception,
    Yz_Exception_InvalidArgument as TypeError,
    Yz_Exception_InvalidArgument as IndexError
;

abstract class Controller_AbstractFetch
    extends \Yz_Controller_Templated
{

    const ERROR_ITEM_NOT_FOUND = ':NotFound';
    const ERROR_INVALID_ARGUMENT = ':InvalidArgument';


    /** The list of required arguments, parsed in order of appearance
     *      for each argument number N in list, call:
     *          set$name($arg[N])
     *      where $name is the argument's name
     *  @var array
     */
    protected $arguments = array(
        'itemId',
    );

    /** The default model's name
     *  @var string|null
     */
    protected $modelName;

    /**
     *  @var Yz_Model_Interface
     */
    protected $model;
    protected $item;
    protected $itemId;
    protected $error;

    /****************************
     *      Public methods      *
     ****************************/

    /** common `template method`
     *  @param Yz_Array
     *  @return this
     */
    public function doGet(Yz_Array $args)
    {
        return $this
            ->checkAccess()         // method of Yz_Controller_Templated
            ->parseArguments($args)
            ->fetchData()
            ->output()              // method of Yz_Controller_Templated
        ;
    }


    /** Custom error handler for entry
     *      Handles item-not-found and invalid-number-of-args
     *
     *  @return this|false
     */
    public function doError( Yz_Exception $ex )
    {
        if ($ex instanceof CtlrArgumentError) {
            return $this->_outputError(self::ERROR_INVALID_ARGUMENT);
        }
        if ($ex instanceof \Yz_Exception_ItemNotFound) {
            return $this->_outputError(self::ERROR_ITEM_NOT_FOUND);
        }
        return false;
    }

    /******************************
     *     Protected methods      *
     ******************************/


    /** parse arguments
     *  @param Yz_Array args (from URI)
     *  @return this
     *  @throw Yz_Controller_Exception_InvalidArgument
     */
    protected function parseArguments(Yz_Array $args)
    {
        if ($this->arguments) {
            if ($args->count() < count($this->arguments))
                throw new CtlrArgumentError("Invalid number of arguments");
            foreach ($this->arguments as $i => $argName) {
                $method = 'set' . $argName;
                try {
                    $this->$method($args[$i]);
                } catch (TypeError $ex) {
                    throw new CtlrArgumentError("Invalid argument value for {$argName}");
                }
            }
        }
        return $this;
    }



    /** parse arguments: obtain itemId
     *  @param string(int) arg (from URI)
     *  @return this
     *  @throw Yz_Controller_Exception_InvalidArgument
     */
    protected function setItemId($arg)
    {
        $this->itemId = Yz_Int::test($arg);
        if ($this->itemId <= 0)
            throw new IndexError;
        return $this;
    }


    /**
     *  @return this
     *
     */
    protected function selectModel()
    {
        debug();
        $model =& $this->model;
        if (! $model)
            $model = $this->module->selectModel($this->modelName);
        return $model;
    }



    /**
     *
     */
    protected function fetchData()
    {
        debug();
        $model = $this->selectModel();
        $this->item = $model->fetchItemById($this->itemId);
        return $this;
    }



    /**
     *  @return this
     *
     */
    protected function assignTemplateParams(\Yz_Template_Interface $t)
    {
        $t->item = $this->item;
        $t->itemId = $this->itemId;
        return $this ;
    }



    /** get an i18n string for (abstract) error message
     *      defaults to :{Name}:Error , where {Name} is the controller's short name e.g. List
     *  @return string
     */
    protected function getErrorMessage()
    {
        return ':' . $this->name . ':Error';
    }

    protected function _outputError($error)
    {
        $t = $this->selectTemplate('Error');
        $t->errorMessage = $this->getErrorMessage() . $error;
        return $this->outputTemplate($t);
    }

}